/* -*- c++ -*- ----------------------------------------------------------
   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
   http://lammps.sandia.gov, Sandia National Laboratories
   Steve Plimpton, sjplimp@sandia.gov

   Copyright (2003) Sandia Corporation.  Under the terms of Contract
   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
   certain rights in this software.  This software is distributed under
   the GNU General Public License.

   See the README file in the top-level LAMMPS directory.
   -----------------------------------------------------------------------

   This file is a part of the USER-MANIFOLD package.

   This package allows LAMMPS to perform MD simulations of particles
   constrained on a manifold (i.e., a 2D subspace of the 3D simulation
   box). It achieves this using the RATTLE constraint algorithm applied
   to single-particle constraint functions g(xi,yi,zi) = 0 and their
   derivative (i.e. the normal of the manifold) n = grad(g).

   It is very easy to add your own manifolds to the current zoo
   (we now have sphere, a dendritic spine approximation, a 2D plane (for
   testing purposes) and a wave-y plane.
   See the README file for more info.

   Stefan Paquay, stefanpaquay@gmail.com
   Applied Physics/Theory of Polymers and Soft Matter,
   Eindhoven University of Technology (TU/e), The Netherlands

   Thanks to Remy Kusters at TU/e for testing.

   This software is distributed under the GNU General Public License.

------------------------------------------------------------------------- */

#ifndef LMP_MANIFOLD_H
#define LMP_MANIFOLD_H

#include "pointers.h"
#include <cmath>

namespace LAMMPS_NS {
namespace user_manifold {

  // Abstract base class.
  class manifold : protected Pointers {
   public:
    manifold(class LAMMPS* lmp) : Pointers(lmp), params(NULL){ }
    virtual ~manifold(){ delete[] params; }
    virtual double g( const double * ) = 0;
    virtual void   n( const double *, double * ) = 0;


    // Variant of g that computes n at the same time.
    virtual double g_and_n( const double *x, double *nn )
    {
      this->n(x,nn);
      return g(x);
    }

    virtual const char *id() = 0;

    virtual void set_atom_id( tagint /*a_id*/ ){}
    virtual int nparams() = 0;
    // double *get_params(){ return params; };

    // Overload if any initialization depends on params:
    virtual void post_param_init(){}
    virtual void checkup(){} // Some diagnostics...

    double *params;
  };



  // Some utility functions that are templated, so I implement them
  // here in the header.
  template< unsigned int size > inline
  double infnorm( double *vect )
  {
    double largest = fabs( vect[0] );
    for( unsigned int i = 1; i < size; ++i ){
      double c = fabs( vect[i] );
      largest = ( c > largest ) ? c : largest;
    }
    return largest;
  }

  inline double dot( double *a, double *b ){
    return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
  }


} // namespace LAMMPS_NS

}


#endif // LMP_MANIFOLD_H
